﻿using eProcurement.DAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.Data.Objects;

namespace eProcurement.BLL
{
    public class Manager
    {
        private eProcurementModelContainer searchcontext = new eProcurementModelContainer();

        public static List<string> GetIndustryCategories( string path )
        {
            return XMLHelper.IndustryCategories( path );
        }

        public bool Login( string username, string pwd )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.AppUsers
                             where i.Username == username && i.Password == pwd
                             select i;

                if ( result.Count() > 0 )
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public bool UserExist( string username )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.AppUsers
                             where i.Username == username
                             select i;

                if ( result.Count() > 0 )
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public bool IsPurchaser( string username )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.AppUsers
                             where i.Username == username
                             select i;

                if ( result.First() is Purchaser )
                {
                    return true;
                }

                return false;
            }
        }

        public AppUser GetAppUser( string username )
        {
            eProcurementModelContainer context = new eProcurementModelContainer();
            var result = ( from i in context.AppUsers
                           where i.Username == username
                           select i ).FirstOrDefault();

            return result;
        }

        public bool UpdateUser( AppUser updateduser )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                AppUser currentuser = ( from i in context.AppUsers
                                        where i.Username == updateduser.Username
                                        select i ).FirstOrDefault();

                if ( currentuser != null )
                {
                    currentuser.Address1 = updateduser.Address1;
                    currentuser.Address2 = updateduser.Address2;
                    currentuser.City = updateduser.City;
                    currentuser.Description = updateduser.Description;
                    currentuser.Fax = updateduser.Fax;
                    currentuser.FirstName = updateduser.FirstName;
                    currentuser.JobTitle = updateduser.JobTitle;
                    currentuser.LastName = updateduser.LastName;
                    currentuser.Telephone = updateduser.Telephone;
                    currentuser.Website = updateduser.Website;

                    return SaveChanges( context );
                }

                return false;
            }
        }

        public bool UpdateAccount( AppUser updateduser )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                AppUser currentuser = ( from i in context.AppUsers
                                        where i.Username == updateduser.Username
                                        select i ).FirstOrDefault();

                if ( currentuser != null )
                {
                    currentuser.Password = currentuser.Password;

                    return SaveChanges( context );
                }

                return false;
            }
        }

        public Project GetProject( int id )
        {
            var result = from i in searchcontext.Projects
                         where i.Id == id
                         select i;

            return result.FirstOrDefault();
        }

        public Project GetMyProject( int id )
        {
            var results = from i in searchcontext.AppUsers.OfType<Purchaser>()
                          from e in i.Projects
                          where e.Id == id
                          select e;

            return results.FirstOrDefault();
        }

        public bool UpdateProject( Project project )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.Projects
                             where i.Id == project.Id
                             select i;

                Project currentproject = result.FirstOrDefault();
                if ( project.ScopeDocument.Length != 0 )
                {
                    currentproject.ScopeFileName = project.ScopeFileName;
                    currentproject.ScopeDocument = project.ScopeDocument;
                    CreateAnnouncement( "Scope Document has been updated", project.Id );
                }
                if ( project.AdditionalDocument.Length != 0 )
                {
                    currentproject.AdditionalDocsName = project.AdditionalDocsName;
                    currentproject.AdditionalDocsName = project.AdditionalDocsName;
                    CreateAnnouncement( "Supporting Documents has been updated", project.Id );
                }
                if ( currentproject.CloseDate != project.CloseDate )
                {
                    CreateAnnouncement( "Project Close Date has been updated", project.Id );
                }
                currentproject.CloseDate = project.CloseDate;
                if ( currentproject.Description != project.Description )
                {
                    CreateAnnouncement( "Project Description has been updated", project.Id );
                }
                currentproject.Description = project.Description;
                currentproject.IndustryCategory = project.IndustryCategory;
                currentproject.State = project.State;
                currentproject.Title = project.Title;

                return SaveChanges( context );
            }
        }

        public bool CancelProject( int id )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = ( from i in context.Projects
                               where i.Id == id
                               select i ).FirstOrDefault();

                result.State = ProjectState.CANCELLED.ToString();

                CreateAnnouncement( "Project has been cancelled. There will be no need to submit bids.", id );

                return SaveChanges( context );
            }
        }

        public bool UpdatePayment( Purchaser updateduser )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                Purchaser currentuser = ( from i in context.AppUsers.OfType<Purchaser>()
                                          where i.Username == updateduser.Username
                                          select i ).FirstOrDefault();

                if ( currentuser != null )
                {
                    currentuser.CC = updateduser.CC;
                    currentuser.Code = updateduser.Code;
                    currentuser.ExpMonth = updateduser.ExpMonth;
                    currentuser.ExpYear = updateduser.ExpYear;
                    currentuser.pAddress1 = updateduser.pAddress1;
                    currentuser.pAddress2 = updateduser.pAddress2;
                    currentuser.pCity = updateduser.pCity;
                    currentuser.pFirstname = updateduser.pFirstname;
                    currentuser.pLastName = updateduser.pLastName;

                    return SaveChanges( context );
                }

                return false;
            }
        }

        public bool AddProject( Project project )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                project.DatePosted = DateTime.Now;
                context.Projects.Add( project );
                return SaveChanges( context );
            }
        }

        public bool AddSupplier( Supplier supplier )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                context.AppUsers.Add( supplier );
                return SaveChanges( context );
            }
        }

        public bool DeleteBid( int id )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = ( from i in context.Bids
                               where i.Id == id
                               select i ).FirstOrDefault();

                if ( result != null )
                {
                    context.Bids.Remove( result );
                    return SaveChanges( context );
                }
                else
                {
                    return false;
                }
            }
        }

        public List<Supplier> GetBidders( int projectid )
        {
            var result = from i in searchcontext.Bids
                         where i.ProjectId == projectid
                         select i.Supplier;

            return result.Distinct().ToList();
        }

        public bool AwardWinner( int bidid )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = ( from i in context.Bids
                               where i.Id == bidid
                               select i ).FirstOrDefault();

                if ( result != null )
                {
                    result.IsWinner = true;
                    Project project = result.Project;
                    project.State = ProjectState.CLOSED.ToString();

                    CreateAnnouncement( "Project CLOSED on " + DateTime.Today.ToShortDateString(), project.Id );
                    CreateAnnouncement( "Bid winner selected: " + result.Supplier.CompanyName, project.Id );

                    return SaveChanges( context );
                }
                else
                {
                    return false;
                }
            }
        }

        public bool PlaceBid( Bid bid )
        {
            var result = from i in searchcontext.Bids
                         where i.ProjectId == bid.ProjectId &&
                         i.SupplierId == bid.SupplierId
                         select i;

            if ( result.Count() == 0 )
            {
                using ( eProcurementModelContainer context = new eProcurementModelContainer() )
                {
                    bid.DateUploaded = DateTime.Now;
                    context.Bids.Add( bid );
                    return SaveChanges( context );
                }
            }
            else
            {
                using ( eProcurementModelContainer context = new eProcurementModelContainer() )
                {
                    var savedbid = ( from i in context.Bids
                                     where i.ProjectId == bid.ProjectId &&
                                     i.SupplierId == bid.SupplierId
                                     select i ).FirstOrDefault();

                    savedbid.Documents = bid.Documents;
                    savedbid.Filename = bid.Filename;
                    savedbid.DateUploaded = DateTime.Now;

                    return SaveChanges( context );
                }
            }
        }

        public List<Bid> GetMyBids( string username )
        {
            return ( (Supplier)GetAppUser( username ) ).Bids.ToList();
        }

        public bool AddPurchaser( Purchaser purchaser )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                context.AppUsers.Add( purchaser );
                return SaveChanges( context );
            }
        }

        public AppUser GetAppUser( Guid id )
        {
            var result = from i in searchcontext.AppUsers
                         where i.Id == id
                         select i;

            return result.FirstOrDefault();
        }

        public List<Project> GetProjects()
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.Projects
                             select i;

                return result.ToList();
            }
        }

        public List<Project> GetProjects( ProjectState state )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                string projectstate = state.ToString();

                var result = from i in context.Projects
                             where i.State == projectstate
                             select i;

                if ( state == ProjectState.OPEN )
                {
                    result = from i in result
                             where EntityFunctions.TruncateTime( i.CloseDate ) > EntityFunctions.TruncateTime( DateTime.Now )
                             select i;
                }

                return result.ToList();
            }
        }

        public List<Project> GetProjectsByCategory( string category )
        {
            string projectstate = ProjectState.OPEN.ToString();

            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.Projects
                             where i.IndustryCategory == category && i.State == projectstate
                             select i;

                return result.ToList();
            }
        }

        public List<Purchaser> GetPurchaserWithOpenProjects()
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.AppUsers.OfType<Purchaser>()
                             from e in i.Projects
                             where EntityFunctions.TruncateTime( e.CloseDate ) > EntityFunctions.TruncateTime( DateTime.Now )
                             select i;

                return result.Distinct().ToList<Purchaser>();
            }
        }

        public List<Purchaser> GetPurchaserIgnoreProjects()
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                var result = from i in context.AppUsers.OfType<Purchaser>()
                             orderby i.CompanyName ascending
                             select i;

                return result.Distinct().ToList<Purchaser>();
            }
        }

        public int GetNumberProjects( string category )
        {
            string projectstate = ProjectState.OPEN.ToString();

            var result = from i in searchcontext.Projects
                         where i.IndustryCategory == category
                         && EntityFunctions.TruncateTime( i.CloseDate ) > EntityFunctions.TruncateTime( DateTime.Now )
                         && i.State == projectstate
                         select i;

            return result.Count();
        }

        private bool SaveChanges( eProcurementModelContainer context )
        {
            try
            {
                context.SaveChanges();
                return true;
            }
            catch ( Exception ex )
            {
                LogError( ex.ToString() + " - " + ex.InnerException );
                return false;
            }
        }

        private void LogError( string error )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                ErrorLog errorlog = new ErrorLog();
                errorlog.Description = error;
                errorlog.DateLogged = DateTime.Now;
                context.ErrorLogs.Add( errorlog );

                context.SaveChanges();
            }
        }

        private void CreateAnnouncement( string description, int projectid )
        {
            using ( eProcurementModelContainer context = new eProcurementModelContainer() )
            {
                Announcement announcement = new Announcement();
                announcement.Description = description;
                announcement.ProjectId = projectid;
                announcement.DatePosted = DateTime.Now;

                context.Announcements.Add( announcement );

                context.SaveChanges();
            }
        }
    }
}
